﻿using System;
using System.Data.SQLite;
using System.IO;
using Dapper;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Net.Security;
using System.Net.Sockets;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel;

namespace Email.Data
{
    public class UserManager
    {
        private string _databaseFilePath;
        private static string basepath = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..", "..", "..", "data"));
        private static string DatabaseFileName = "register.db";
        private static string DatabaseFilePath = Path.GetFullPath(Path.Combine(basepath, DatabaseFileName));
        private static string ConnectionString = $"Data Source={DatabaseFilePath}";
        private static string logFilePath = Path.Combine(basepath,"logs", "log.txt");

        public UserManager(string connectionString)
        {
            string _connectionString = connectionString;
            _databaseFilePath = new SQLiteConnectionStringBuilder(connectionString).DataSource;
            EnsureDatabaseAndPathExist();
        }
        public UserManager()
        {
            _databaseFilePath = new SQLiteConnectionStringBuilder(ConnectionString).DataSource;
            EnsureDatabaseAndPathExist();
        }
        public static SQLiteConnection GetDatabaseConnection()
        {
            try
            {
                Log("\n");
                /*Log("connecting the dataset……");*/
                if (!File.Exists(DatabaseFilePath))
                {
                    Log($"Database file not found at path,initial first please: {DatabaseFilePath}");
                    throw new FileNotFoundException($"Database file not found at path: {DatabaseFilePath}");
                }

                var connection = new SQLiteConnection(ConnectionString);
                connection.Open();
                Log("successfully connected the dataset");
                return connection;
            }
            catch (Exception ex)
            {
                Log($"Failed to connect to the database file: {DatabaseFileName}. DatabaseFilePath: {DatabaseFilePath}");
                throw new Exception($" database file: {DatabaseFilePath}");
            }
        }
        private void EnsureDatabaseAndPathExist()
        {

            string directoryPath = Path.GetDirectoryName(_databaseFilePath);
            if (!Directory.Exists(directoryPath))
            {
                Log("create path for dataset");
                Directory.CreateDirectory(directoryPath);
            }

            if (!File.Exists(_databaseFilePath))
            {
                
                SQLiteConnection.CreateFile(_databaseFilePath);
                Log("There is no such dataset.Now create database.");
                if (File.Exists(logFilePath))
                {
                    CreateNewLogFile();
                }
                InitializeDatabase();
                Log("Initial finish!");
            }
        }
        private void CreateNewLogFile()
        {
            string logDirectory = Path.Combine(basepath, "logs");
            if (!Directory.Exists(logDirectory))
            {
                Directory.CreateDirectory(logDirectory);
            }

            // 生成带有时间戳的日志文件名
            string timestamp = DateTime.Now.ToString("MMddHHmm");
            string logFileName = $"log_{timestamp}.txt";
            logFilePath = Path.Combine(logDirectory, logFileName);

            // 创建一个新的日志文件
            using (FileStream fs = File.Create(logFilePath))
            {
                
                byte[] info = new UTF8Encoding(true).GetBytes($"Log file created at {DateTime.Now}.\n");
                fs.Write(info, 0, info.Length);
            }
        }
        private void InitializeDatabase()
        {
            Log($"Initial begin.DatabaseFilePath: {DatabaseFilePath}");
            try
            {
                using (var connection = GetDatabaseConnection())
                {
                    string tableCommand = @"
                    CREATE TABLE IF NOT EXISTS Users (
                        Id INTEGER PRIMARY KEY AUTOINCREMENT,
                        Username TEXT NOT NULL UNIQUE,
                        PasswordHash TEXT NOT NULL,
                        SmtpAuthCode TEXT 
                    )";
                    var createTable = new SQLiteCommand(tableCommand, connection);
                    createTable.ExecuteNonQuery();
                    Log("Database table 'Users' created successfully.");
                }
            }
            catch (Exception ex)
            {
                Log($"Error creating database table: {ex.Message}");
                throw;
            }

        }
        private bool VerifySmtpAuthCode(string username, string smtpAuthCode)
        {
            try
            {
                using (var client = new TcpClient("pop.qq.com", 995))
                using (var networkStream = client.GetStream())
                using (var sslStream = new SslStream(networkStream))
                {
                    sslStream.AuthenticateAsClient("pop.qq.com");
                    using (var writer = new StreamWriter(sslStream, Encoding.ASCII) { AutoFlush = true })
                    using (var reader = new StreamReader(sslStream, Encoding.ASCII))
                    {
                        // 读取服务器欢迎消息
                        reader.ReadLine();

                        // 发送USER命令
                        writer.WriteLine($"USER {username}");
                        writer.Flush();
                        reader.ReadLine();

                        // 发送PASS命令
                        writer.WriteLine($"PASS {smtpAuthCode}");
                        writer.Flush();
                        reader.ReadLine();
                    }
                }
                return true;
            }
            catch (Exception ex)
            {
                Log($"SMTP verification failed: {ex.Message}");
                return false;
            }
        }
        public string GetSmtpAuthCode(string username)
        {
            using (var connection = UserManager.GetDatabaseConnection())
            {
                var sql = "SELECT SmtpAuthCode FROM Users WHERE Username = @Username";
                return connection.Query<string>(sql, new { Username = username }).FirstOrDefault();
            }
        }
        public void RegisterUser(string username, string password, string smtpAuthCode)
        {
            if (IsUsernameTaken(username))
            {
                Log($"Attempt to register with an existing username: {username}");
                throw new Exception("用户名已存在，请选择其他用户名。");
            }
            if (!VerifySmtpAuthCode(username, smtpAuthCode))
            {
                Log($"Invalid SMTP authorization code for username: {username}");
                throw new Exception("SMTP授权码无效，请检查后重新输入。");
            }
            string passwordHash = HashPassword(password);
            using (var connection = UserManager.GetDatabaseConnection())
            {
                var sql = "INSERT INTO Users (Username, PasswordHash, SmtpAuthCode) VALUES (@Username, @PasswordHash, @SmtpAuthCode)";
                connection.Execute(sql, new { Username = username, PasswordHash = passwordHash, SmtpAuthCode = smtpAuthCode });
                Log($"register {username}，password：{password} successfully");
            }
        }

        public bool IsUsernameTaken(string username)
        {
            using (var connection = GetDatabaseConnection())
            {
                var sql = "SELECT COUNT(1) FROM Users WHERE Username = @Username";
                return connection.Query<int>(sql, new { Username = username }).Single() > 0;
            }
        }

        public bool ValidateUser(string username, string password)
        {
            string passwordHash = HashPassword(password);
            using (var connection = UserManager.GetDatabaseConnection())
            {
                var sql = "SELECT COUNT(1) FROM Users WHERE Username = @Username AND PasswordHash = @PasswordHash";
                Log("excute Validate User's name.");
                return connection.Query<int>(sql, new { Username = username, PasswordHash = passwordHash }).Single() > 0;
            }
        }
        public void DeleteSmtpAuthCode(string username)
        {
            using (var connection = UserManager.GetDatabaseConnection())
            {
                var sql = "UPDATE Users SET SmtpAuthCode = NULL WHERE Username = @Username";
                connection.Execute(sql, new { Username = username });
                Log($"SMTP授权码已从用户名为{username}的记录中删除。");
            }
        }

        private string HashPassword(string password)
        {
            using (var sha256 = SHA256.Create())
            {
                byte[] bytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(password));
                var builder = new StringBuilder();
                for (int i = 0; i < bytes.Length; i++)
                {
                    builder.Append(bytes[i].ToString("x2"));
                }
                return builder.ToString();
            }
        }

        private static void Log(string message)
        {
            /*string timestamp = DateTime.Now.ToString("MMddHHmm");
            string logFileName = $"log_{timestamp}.txt";
            string logFilePath = Path.Combine(basepath, "logs", logFileName);*/
            Directory.CreateDirectory(Path.GetDirectoryName(logFilePath)); // Ensure the directory exists
            using (StreamWriter writer = new StreamWriter(logFilePath, true))
            {
                if (message != "\n")
                {
                    writer.WriteLine($"{DateTime.Now}: {message}");
                }
                else
                {
                    writer.WriteLine("");
                }
            }
        }
    }
}
